package com.quanyan.stadium.service.gameRules.impl;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.quanyan.common.utils.StringUtil;
import com.quanyan.stadium.biz.BizGameSystemDao;
import com.quanyan.stadium.entity.TbGameRound;
import com.quanyan.stadium.entity.TbGameRoundScore;
import com.quanyan.stadium.entity.vo.GameGroup;
import com.quanyan.stadium.service.gameRules.GameSystemService;
import com.quanyan.stadium.utils.GameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by xiao.lai on 16/5/26.
 */
@Service("gameSystemServiceImpl")
public class GameSystemServiceImpl implements GameSystemService{

    private final static Logger logger = LoggerFactory.getLogger(GameSystemServiceImpl.class);

    @Autowired
    private BizGameSystemDao bizGameSystemDao;


    public List<GameGroup> washedGroup(List<Integer> teamIds, TbGameRound tbGameRound, boolean isFirstRound) {
        if (isFirstRound) {
            return this.washedGroupFirst(teamIds, tbGameRound);
        }else {
            return this.washedGroupNotFirst(teamIds, tbGameRound);
        }

    }

    private List<GameGroup> washedGroupFirst(List<Integer> teamIds, TbGameRound tbGameRound) {
        //需要将teamIds
        List<GameGroup> gameGroups = new ArrayList<>();
        int expectTeamNum = (int) Math.pow(2, GameUtils.washedRoundleNum((double) teamIds.size()));
        int diffTeamNum = expectTeamNum - teamIds.size();
        int m = teamIds.size() % 2, n = teamIds.size() / 2, j;
        if (diffTeamNum > 0) {
            List<Integer> tempIds = new ArrayList<>();
            for (int i=0;i<diffTeamNum;i++) {
                GameGroup group = new GameGroup();
                group.setGroup(1);
                group.setGameRoundId(tbGameRound.getId());
                group.setTeamHomeId(teamIds.get(i));
                group.setIsWin(true);
                gameGroups.add(group);
                tempIds.add(teamIds.get(i));
            }
            teamIds.removeAll(tempIds);
            n = teamIds.size() / 2;
            for (j = 0; j < n; j++) {
                GameGroup group = new GameGroup();
                group.setGroup(1);
                group.setGameRoundId(tbGameRound.getId());
                group.setTeamHomeId(teamIds.get(j));
                group.setTeamAwayId(teamIds.get(n * 2 - 1 - j));
                gameGroups.add(group);
            }
        }else {
            if (m != 0) {
                GameGroup group = new GameGroup();
                group.setGroup(1);
                group.setGameRoundId(tbGameRound.getId());
                group.setTeamHomeId(teamIds.get(0));
                gameGroups.add(group);
                teamIds.remove(0);
            }
            for (j = 0; j < n; j++) {
                GameGroup group = new GameGroup();
                group.setGroup(1);
                group.setGameRoundId(tbGameRound.getId());
                group.setTeamHomeId(teamIds.get(j));
                group.setTeamAwayId(teamIds.get(n * 2 - 1 - j));
                gameGroups.add(group);
            }
        }
        return gameGroups;
    }


    private List<GameGroup> washedGroupNotFirst(List<Integer> teamIds, TbGameRound tbGameRound) {
        //这里获取到的list已经经过上一轮处理得到的按赛程排列的,而且这里的队伍均是偶数
        List<GameGroup> gameGroups = new ArrayList<>();
        int n = teamIds.size() / 2;
        for (int j = 0; j < n; j++) {
            GameGroup group = new GameGroup();
            group.setGroup(1);
            group.setGameRoundId(tbGameRound.getId());
            group.setTeamHomeId(teamIds.get(2*j));
            group.setTeamAwayId(teamIds.get(2*j+1));
            gameGroups.add(group);
        }
        return gameGroups;
    }


    public List<GameGroup> circleGroup(List<Integer> tempIds, List<TbGameRound> tbGameRoundList, int group, Integer teamType) {
        //初始化轮次数目
        Collections.sort(tbGameRoundList, new Comparator<TbGameRound>() {
            public int compare(TbGameRound o1, TbGameRound o2) {
                return o1.getId().compareTo(o2.getId());
            }
        });

        //解决sublist问题
        List<Integer> teamIds = new ArrayList<>();
        teamIds.addAll(tempIds);

        int curRoundNum = GameUtils.circleRoundNum((double) teamIds.size());    //期待队伍数量
        if (tbGameRoundList.size() != curRoundNum) {                //索取前几轮,将队伍匹配
            tbGameRoundList = tbGameRoundList.subList(0, curRoundNum);
        }
        int n = teamIds.size(),len;
        if(n%2==0) {        // 偶数倒序编排
            len=n;
            return this.circleGroup1(len, teamIds, tbGameRoundList, group);
        } else {            //奇数贝格尔编排
            len=n+1;
            teamIds.add(0);
            return this.circleGroup2(len, teamIds, tbGameRoundList, group);
        }

    }

    /**
     * 普通方法,一般编排方法
     *
     * */
    private List<GameGroup> circleGroup1(int len, List<Integer> teamIds, List<TbGameRound> tbGameRoundList, int group) {
        List<GameGroup> result = new ArrayList<>();
        for(int i=1;i< len;i++) {
            for(int j=0;j< len/2;j++)
            {
                GameGroup gameGroupTemp = new GameGroup();
                gameGroupTemp.setGroup(group);
                gameGroupTemp.setGameRoundId(tbGameRoundList.get(i-1).getId());
                gameGroupTemp.setTeamHomeId(teamIds.get(j));
                gameGroupTemp.setTeamAwayId(teamIds.get(len-1-j));
                result.add(gameGroupTemp);
            }
            Integer temp=teamIds.get(len-1); //将最后一队的值赋给临时变量temp
            for(int k=len-1;k>0;k--)
            {
                teamIds.set(k, teamIds.get(k-1));
            }
            teamIds.set(1, temp); //将临时变量temp赋给数组的第二值
        }
        return result;
    }

    /**
     * 贝格尔
     *
     * */
    private List<GameGroup> circleGroup2(int m, List<Integer> teamIds, List<TbGameRound> tbGameRoundList, int group) {
        List<GameGroup> result = new ArrayList<>();
        int a=1,b=1,index=1,loop=0;
        for(int i=1; i<=(m-1)*(m/2); i++)
        {
            if(a>=m) a=1;
            if(index>m/2) index=1;
            if(index==1){
                loop++;
                if(i==1){
                    b=m;
                }else{
                    b=a;
                }
                if(((i-1)/(m/2))%2==0){
                    GameGroup gameGroupTemp = new GameGroup();
                    gameGroupTemp.setGroup(group);
                    gameGroupTemp.setGameRoundId(tbGameRoundList.get(loop-1).getId());
                    if (teamIds.get(a-1) == 0) {
                        gameGroupTemp.setTeamHomeId(teamIds.get(m-1));
                        gameGroupTemp.setTeamAwayId(teamIds.get(a-1));
                    }else {
                        gameGroupTemp.setTeamHomeId(teamIds.get(a-1));
                        gameGroupTemp.setTeamAwayId(teamIds.get(m-1));
                    }
                    result.add(gameGroupTemp);
                }else{
                    GameGroup gameGroupTemp = new GameGroup();
                    gameGroupTemp.setGroup(group);
                    gameGroupTemp.setGameRoundId(tbGameRoundList.get(loop-1).getId());
                    if (teamIds.get(m-1) == 0) {
                        gameGroupTemp.setTeamHomeId(teamIds.get(a-1));
                        gameGroupTemp.setTeamAwayId(teamIds.get(m-1));
                    }else {
                        gameGroupTemp.setTeamHomeId(teamIds.get(m-1));
                        gameGroupTemp.setTeamAwayId(teamIds.get(a-1));
                    }
                    result.add(gameGroupTemp);
                }
            }else if(index>1 && index<=m/2){
                if(b>1) b--;
                else b=m-1;
                GameGroup gameGroupTemp = new GameGroup();
                gameGroupTemp.setGroup(group);
                gameGroupTemp.setGameRoundId(tbGameRoundList.get(loop-1).getId());
                gameGroupTemp.setTeamHomeId(teamIds.get(a-1));
                gameGroupTemp.setTeamAwayId(teamIds.get(b-1));
                result.add(gameGroupTemp);
            }
            index++;
            a++;
        }
        return result;
    }

    @Override
    public List<GameGroup> swissGroup(List<Integer> teamIds, TbGameRound tbGameRound, boolean isFirstRound) {
        List<GameGroup> gameGroups = new ArrayList<>();
        List<Integer> passTeamList = new ArrayList<>();
        int m = teamIds.size() % 2, n = teamIds.size() / 2, j;
        if (m != 0) {
            GameGroup group = new GameGroup();
            group.setGroup(1);
            group.setGameRoundId(tbGameRound.getId());
            group.setTeamHomeId(teamIds.get(0));
            group.setIsWin(true);
            gameGroups.add(group);
            passTeamList.add(teamIds.get(0));
            teamIds.remove(0);
        }
        if (isFirstRound) {
            //随机排序
            while (n>0) {
                GameGroup group = new GameGroup();
                group.setGameRoundId(tbGameRound.getId());
                group.setGroup(1);
                int x = (int)(Math.random()*teamIds.size());
                group.setTeamHomeId(teamIds.get(x));
                teamIds.remove(teamIds.get(x));
                int y = (int)(Math.random()*teamIds.size());
                group.setTeamAwayId(teamIds.get(y));
                teamIds.remove(teamIds.get(y));
                n--;
                gameGroups.add(group);
            }

        } else {
            //首尾匹配
            for (j = 0; j < n; j++) {
                GameGroup group = new GameGroup();
                group.setGroup(1);
                group.setGameRoundId(tbGameRound.getId());
                group.setTeamHomeId(teamIds.get(j));
                group.setTeamAwayId(teamIds.get(teamIds.size() - 1 - j));
                gameGroups.add(group);
            }
        }
        //更新上一轮轮次(因为第一轮的缘故),轮空的队伍
        Gson gson = new Gson();
        TbGameRound round = new TbGameRound();
        round.setId(tbGameRound.getId());
        round.setPassTeam(gson.toJson(passTeamList));
        bizGameSystemDao.updateTbGameRound(round);

        return gameGroups;
    }


    public List<GameGroup> swissGroupNotFirst(TbGameRound tbGameRound, List<TbGameRoundScore> tbGameRoundScores, Integer preGameRoundId) {
        List<GameGroup> gameGroups = new ArrayList<>();
        List<Integer> curPassTeamList = new ArrayList<>();
        Gson gson = new Gson();
        //对分数进行归位
        Map<Double , Set<Integer>> scoreTeamMap = new HashMap<>();
        for (TbGameRoundScore tbGameRoundScore : tbGameRoundScores) {
            Set<Integer> teamSet = scoreTeamMap.get(tbGameRoundScore.getScore());
            if (null == teamSet || teamSet.size() < 1) {
                teamSet = new HashSet<>();
            }
            teamSet.add(tbGameRoundScore.getGameEventTeamId());
            scoreTeamMap.put(tbGameRoundScore.getScore(), teamSet);
        }

        //获取上一轮,轮空的队伍
        TbGameRound preTbGameRound = bizGameSystemDao.selectTbGameRound(preGameRoundId);
        List<Integer> hisToryPassTeam = new ArrayList<>();
        String oldPassTemp = preTbGameRound.getPassTeam();
        if (!StringUtil.isBlankOrNull(oldPassTemp)) {
            hisToryPassTeam = gson.fromJson(oldPassTemp, new TypeToken<List<Integer>>() {}.getType());
        }


        //根据分数级别的
        for (Map.Entry<Double , Set<Integer>> entry : scoreTeamMap.entrySet()) {
            List<Integer> teamList = new ArrayList<>(entry.getValue());
            if (teamList.size() % 2 != 0) { //轮空从没有被轮空的
                GameGroup gameGroup = new GameGroup();
                gameGroup.setGameRoundId(tbGameRound.getId());
                gameGroup.setIsWin(true);
                gameGroup.setGroup(1);
                gameGroup.setTeamAwayId(0);
                if (null!=hisToryPassTeam && hisToryPassTeam.size() >0 && teamList.size() > 1) {
                    List<Integer> temp = teamList;
                    temp.removeAll(hisToryPassTeam);
                    if (temp.size() > 0) {
                        gameGroup.setTeamHomeId(temp.get(0));
                        curPassTeamList.add(temp.get(0));
                        teamList.remove(temp.get(0));
                    }else {
                        gameGroup.setTeamHomeId(teamList.get(0));
                        curPassTeamList.add(teamList.get(0));
                        teamList.remove(0);
                    }
                }else {
                    gameGroup.setTeamHomeId(teamList.get(0));
                    curPassTeamList.add(teamList.get(0));
                    teamList.remove(0);
                }
                gameGroups.add(gameGroup);
            }
            if (teamList.size() > 0) {
                for (int i=0;i<teamList.size()/2;i++) {
                    GameGroup gameGroup = new GameGroup();
                    gameGroup.setGameRoundId(tbGameRound.getId());
                    gameGroup.setGroup(1);
                    gameGroup.setTeamHomeId(teamList.get(i));
                    gameGroup.setTeamAwayId(teamList.get(teamList.size() - 1 - i));
                    gameGroups.add(gameGroup);
                }
            }
        }

        //更新上一轮轮次,轮空的队伍
        TbGameRound round = new TbGameRound();
        round.setId(preGameRoundId);
        round.setPassTeam(gson.toJson(curPassTeamList));
        bizGameSystemDao.updateTbGameRound(round);
        return gameGroups;
    }


    public List<GameGroup> swissGroupNew(List<Integer> teamIds, TbGameRound tbGameRound, Integer preGameRoundId, boolean isFirst) {
        List<GameGroup> gameGroups = new ArrayList<>();
        //更新上一轮轮次(因为第一轮的缘故),轮空的队伍

        Gson gson = new Gson();
        List<Integer> passTeam = new ArrayList<>();
        Map<Integer, Set<Integer>> gameGroup = new HashMap<>();
        if (isFirst) {
            for (Integer temp : teamIds) {
                List<Integer> temps = new ArrayList<>();
                temps.addAll(teamIds);
                temps.remove(temp);
                gameGroup.put(temp, new HashSet<Integer>(temps));
            }
        }else {
            TbGameRound preGameRound = bizGameSystemDao.selectTbGameRound(preGameRoundId);
            gameGroup = gson.fromJson(preGameRound.getMatchTeam(),
                    new TypeToken<Map<Integer, Set<Integer>>>() {}.getType());
            passTeam = gson.fromJson(preGameRound.getPassTeam(),
                    new TypeToken<List<Integer>>() {}.getType());
        }

        //处理轮空问题队伍
        if (teamIds.size()%2 != 0) {
            for (Integer temp : teamIds) {
                if (!passTeam.contains(temp)) {
                    GameGroup group = new GameGroup();
                    group.setGroup(1);
                    group.setGameRoundId(tbGameRound.getId());
                    group.setTeamHomeId(temp);
                    group.setIsWin(true);
                    group.setTeamAwayId(0);
                    gameGroups.add(group);
                    passTeam.add(temp);
                    teamIds.remove(temp);
                    break;
                }
            }
        }

        //单数 由小到大,双数大到小  (testN 安全值,防止出现异常问题)
        int testN = 500;
        boolean evenRound = tbGameRound.getRoundStatus()%2==0?true:false;
        int index2 = !evenRound?(teamIds.size()-2):1;
        boolean breakFlag = false;
        while (teamIds.size()>0 && testN>0) {
            testN--;
            if (breakFlag) {
                index2 = !evenRound?(teamIds.size()-2):1;
            }
            int index1 = !evenRound?(teamIds.size()-1):0;
            List<Integer> setTemp = new ArrayList<>(gameGroup.get(teamIds.get(index1)));
            if (setTemp.contains(teamIds.get(index2))) {
                GameGroup group = new GameGroup();
                group.setGroup(1);
                group.setGameRoundId(tbGameRound.getId());

                group.setTeamHomeId(teamIds.get(index1));
                group.setTeamAwayId(teamIds.get(index2));
                gameGroups.add(group);

                Set<Integer> setTemp1 = gameGroup.get(teamIds.get(index1));
                Set<Integer> setTemp2 = gameGroup.get(teamIds.get(index2));
                setTemp1.remove(teamIds.get(index2));
                setTemp2.remove(teamIds.get(index1));

                gameGroup.put(teamIds.get(index1), setTemp1);
                gameGroup.put(teamIds.get(index2), setTemp2);

                teamIds.remove(index1);
                if (!evenRound) {
                    teamIds.remove(index2);
                }else {
                    teamIds.remove(index2-1);
                }

                breakFlag = true;
            }else if(!setTemp.contains(teamIds.get(index2)) && teamIds.size() == 2){
                this.updateLastError(teamIds, gameGroup, gameGroups, tbGameRound);
            }else {
                breakFlag = false;
            }
            if (!evenRound) {
                index2--;
            }else {
                index2++;
            }
        }
        
        //更新上一轮轮次,轮空的队伍
        TbGameRound round = new TbGameRound();
        round.setId(tbGameRound.getId());
        round.setPassTeam(gson.toJson(passTeam));
        round.setMatchTeam(gson.toJson(gameGroup));
        bizGameSystemDao.updateTbGameRound(round);

        return gameGroups;
    }


    /**
     * 处理最后一轮出现的最后一组出现重复的问题
     *
     * @param ids        队伍集合
     * @param gameGroups 当前轮次下所有赛程对战
     * @param gameGroup  当前轮次下某一赛程对战
     * @param tbGameRound 当前轮次基本对象
     *
     * */
    private void updateLastError(List<Integer> ids, Map<Integer, Set<Integer>> gameGroup, List<GameGroup> gameGroups, TbGameRound tbGameRound){
        int groupNum = gameGroups.size();
        while (groupNum>0) {
            GameGroup group = gameGroups.get(groupNum-1);  //最后一组
            int homeId = group.getTeamHomeId();
            int awayId = group.getTeamAwayId();

            List<Integer> homeTemp = new ArrayList<>(gameGroup.get(homeId));
            List<Integer> awayTemp = new ArrayList<>(gameGroup.get(awayId));

            boolean isGood = false;

            if (homeTemp.contains(ids.get(0)) && awayTemp.contains(ids.get(1))) {
                this.findMatchGroup(ids, gameGroup, gameGroups, tbGameRound, homeId,  awayId,  0,  1,  groupNum);
                isGood = true;
            }

            if (isGood) {
                return;
            }
            if (homeTemp.contains(ids.get(1)) && awayTemp.contains(ids.get(0))) {
                this.findMatchGroup(ids, gameGroup, gameGroups, tbGameRound, homeId, awayId, 1, 0, groupNum);
                isGood = true;
            }

            if (isGood) {
                return;
            }

            groupNum--;

            if (groupNum == 0) {
                logger.debug("瑞士制,某一轮的最后一个赛程,出现无法解决重复的问题,当前轮次ID:{}", tbGameRound.getId());
                this.exceptionLastGameSchedule(ids, gameGroup,  gameGroups,  tbGameRound, homeId,  awayId);
                return;
            }
        }
    }

    /**
     * 处理最后一轮异常情况
     *
     * @param ids
     * @param gameGroup
     * @param gameGroups
     * @param tbGameRound
     * @param homeId
     * @param awayId
     *
     *
     * */
    private void exceptionLastGameSchedule(List<Integer> ids, Map<Integer, Set<Integer>> gameGroup, List<GameGroup> gameGroups, TbGameRound tbGameRound,
                      Integer homeId, Integer awayId){
        GameGroup group1 = new GameGroup();
        group1.setGroup(1);
        group1.setGameRoundId(tbGameRound.getId());
        group1.setTeamHomeId(ids.get(0));
        group1.setTeamAwayId(ids.get(1));
        gameGroups.add(group1);

        Set<Integer> setTemp1 = gameGroup.get(homeId);
        Set<Integer> setTemp2 = gameGroup.get(awayId);

        setTemp1.remove(ids.get(1));
        setTemp2.remove(ids.get(0));

        gameGroup.put(ids.get(0), setTemp1);
        gameGroup.put(ids.get(1), setTemp2);

        ids.clear();
    }


    /**
     * 开始匹配
     *
     * @param ids
     * @param gameGroup
     * @param gameGroups
     * @param tbGameRound
     * @param homeId
     * @param awayId
     * @param homeIndex
     * @param awayIndex
     * @param groupNum
     *
     *
     * */
    private void findMatchGroup(List<Integer> ids, Map<Integer, Set<Integer>> gameGroup, List<GameGroup> gameGroups, TbGameRound tbGameRound,
                      Integer homeId, Integer awayId, Integer homeIndex, Integer awayIndex, Integer groupNum){
        GameGroup group1 = new GameGroup();
        group1.setGroup(1);
        group1.setGameRoundId(tbGameRound.getId());
        group1.setTeamHomeId(homeId);
        group1.setTeamAwayId(ids.get(homeIndex));
        gameGroups.set(groupNum - 1, group1);


        GameGroup group2 = new GameGroup();
        group2.setGroup(1);
        group2.setGameRoundId(tbGameRound.getId());
        group2.setTeamHomeId(awayId);
        group2.setTeamAwayId(ids.get(awayIndex));
        gameGroups.add(group2);


        Set<Integer> setTemp1 = gameGroup.get(homeId);
        Set<Integer> setTemp2 = gameGroup.get(awayId);
        Set<Integer> setTemp3 = gameGroup.get(ids.get(awayIndex));
        Set<Integer> setTemp4 = gameGroup.get(ids.get(homeIndex));

        setTemp1.remove(ids.get(homeIndex));
        setTemp1.add(awayId);
        setTemp2.remove(ids.get(awayIndex));
        setTemp2.add(homeId);


        setTemp3.remove(awayId);
        setTemp4.remove(homeId);

        gameGroup.put(homeId, setTemp1);
        gameGroup.put(awayId, setTemp2);
        gameGroup.put(ids.get(awayIndex), setTemp3);
        gameGroup.put(ids.get(homeIndex), setTemp4);

        ids.clear();
    }
}
